<?php

// ===================
// = CError handling =
// ===================
CRequireIfPHP4('CError');

/**
	A CError code for a request not coming from Second Life.
	An error of this code indicates that the request does not come
	from the IP of a known Second Life simulator.
*/
define ('kSLNotSecondLifeRequest', 'kSLNotSecondLifeRequest');
/** Private. */
function _SLNotSecondLifeRequest($reason) {
	return new CError(kSLNotSecondLifeRequest,
		"A request coming from Second Life was expected, but the request does not seem to come from Second Life simulators.",
		$reason);
}

/**
	A CError code for a malformed request from Second Life.
	An error with this code indicates that the request does not
	identify the user agent as a Second Life simulator.
*/
define ('kSLUserAgentNotSecondLife', 'kSLUserAgentNotSecondLife');
/** Private. */
function _SLUserAgentNotSecondLife($reason) {
	return new CError(kSLHeadersNotFound,
		"A request coming from Second Life was expected, but the request does not identify its user agent as a Second Life simulator.",
		$reason);	
}

/**
	A CError code for a malformed request from Second Life.
	An error with this code indicates that the request lacks one
	or more of the custom headers that are sent by llHTTPRequest().
*/
define ('kSLHeadersNotFound', 'kSLHeadersNotFound');
/** Private. */
function _SLHeadersNotFound($reason) {
	return new CError(kSLHeadersNotFound,
		"A request coming from Second Life was expected, but the request did not include the required extended headers.",
		$reason);	
}

// ===========================
// = Info from the simulator =
// ===========================

/**
Returns true if the request seems to be coming from Second Life, false otherwise.
*/
function SLIsSecondLife() {
	return CErr(SLFindIfSecondLife()) === false;
}

/** Private. */
$GLOBALS['_SLIPBlocks'] = array(
	array(ip2long('63.210.156.0'), 1024),
	array(ip2long('64.129.40.0'), 2048),
	array(ip2long('64.154.220.0'), 1024),
	array(ip2long('66.150.244.0'), 512),
	array(ip2long('69.25.104.0'), 512),
	array(ip2long('72.5.12.0'), 1024),
);

/**
Returns true if the request seems to be coming from Second Life, or a CError if it doesn't seem to.
*/
function SLFindIfSecondLife() {
	$shard = @$_SERVER['HTTP_X_SECONDLIFE_SHARD'];
	$ua = @$_SERVER['USER_AGENT'];
	$ip = @ip2long($_SERVER['REMOTE_ADDR']);
	
	if (!CHasSubstring($ua, "Second Life/"))
		return _SLUserAgentNotSecondLife(null);
	
	if (is_null($shard))
		return _SLHeadersNotFound(null);
		
	if (!is_null($ip)) {
		foreach ($GLOBALS['_SLIPBlocks'] as $block) {
			if ($ip >= $block[0] && $ip <= $block[0] + $block[1] - 1)
				return true;
		}
	}
	
	return _SLNotSecondLifeRequest(null);
}

/**
Triggers an error or an exception if the request doesn't seem to be
coming from Second Life.
*/
function SLRequireSecondLife() {
	$r = SLFindIfSecondLife();
	
	if (CErr($r))
		$r->Raise();
}

/**
Returns an object whose properties contain additional information
sent by llHTTPRequest() to this script. The object is of a class
compatible with SLInfo. See the SLInfo class's documentation for
details.
*/
function &SLRequestInfo() {
	static $info = null;
	if (!$info) {
		CRequireIfPHP4('SLInfo');
		$info = &new SLInfo();
	}
	
	return $info;
}

// ===========
// = Helpers =
// ===========

/**
Returns a string formatted exactly as the llMD5String() function would
do in a LSL script.
*/
function SLMD5String($string, $nonce) {
	return strtolower(md5($string . ':' . (string) $nonce));
}

/**
Returns a string that can be parsed by the llCSV2List() function, starting
from a PHP array.

The resulting CSV will not have any of the keys of the array, only the values. To preserve keys, turn them into values by using the SLEncodeListWithKeys() function instead.

The items of the list are URL-encoded. See below for details.

@param array An array to encode into a string.
@param literal If false or unspecified, each of the strings will be URL-encoded. If true, they will be kept as they are, or produce an error if they cannot be sent without encoding. This may happen if the items in the array may contain the ',' character. Note that this requires you to use llUnescapeURL() on elements of the list returned by llCSV2List() before you can read them (or use the supplied SLDecodeList function).
@return The string or a CError with the kCMalformedData error code if the array contains values that cannot be converted to strings or are illegal in the final string.
*/
function SLEncodeList($array, $literal = null) {
	$s = '';
	$first = true;
	
	foreach ($array as $value) {
		if (is_array($value) || is_object($value))
			return CError::MalformedData(null);
		$v = (string) $value;
		
		if ($literal) {
			if (strpos($v, ',') !== false)
				return CError::MalformedData(null);
		} else
			$v = urlencode($v);
		
		if (!$first)
			$s .= ',';
		$first = false;
		$s .= $v;
	}
	
	return str_replace("+", "%20", $s);
}

/**
As SLEncodeList(), except the keys are preserved by making them elements of the list as follows: [key0, value0, key1, value1, ...].

@see SLEncodeList
*/
function SLEncodeListWithKeys($array, $urlencode = null) {
	$a = array();
	foreach ($array as $key => $val) {
		$a[] = $key;
		$a[] = $val;
	}
	
	return SLEncodeList($a, $urlencode);
}

?>